#include "common.h"
#include "PlainPolygonRenderer.h"


using namespace Scenic::Renderer;


static void __stdcall tessBegin(GLenum mode)
{
	if(mode != GL_TRIANGLES)
	{
		printf("NOT TRIANGLES!!!\n");
	}
}

static void __stdcall tessEnd()
{
}

static void __stdcall tessEdgeFlag(GLboolean flag, PlainPolygonRenderer *renderer)
{
	renderer->edgeFlag(flag ? true : false);
}

static void __stdcall tessCombineFunc(double coords[3], struct TessVertex *d[4], float w[4], struct TessVertex **dataOut,
							PlainPolygonRenderer *renderer)
{
	renderer->combineFunc(coords, d, w, dataOut);
}

static void __stdcall tessVertexFunc(struct TessVertex *data, PlainPolygonRenderer *renderer)
{
	renderer->vertexFunc(data);
}


PlainPolygonRenderer::PlainPolygonRenderer(Context *context)
{
	this->context = context;
	vs = new VertexStore(VSF_TEX0, context, 0);
	triangleIndex = 0;
}

PlainPolygonRenderer::~PlainPolygonRenderer()
{
	delete vs;
}

void PlainPolygonRenderer::begin()
{
	context->setPrimitives(0);
	tessObj = gluNewTess();

	gluTessNormal(tessObj, 0, 0, 1);
	gluTessProperty(tessObj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
	gluTessCallback(tessObj, GLU_TESS_BEGIN, (GLvoid (__stdcall *)())tessBegin);
	gluTessCallback(tessObj, GLU_TESS_VERTEX_DATA, (GLvoid (__stdcall *)())tessVertexFunc); 
	gluTessCallback(tessObj, GLU_TESS_END, (GLvoid (__stdcall *)())tessEnd);
	gluTessCallback(tessObj, GLU_TESS_COMBINE_DATA, (GLvoid (__stdcall *)())tessCombineFunc);
	gluTessCallback(tessObj, GLU_TESS_EDGE_FLAG_DATA, (GLvoid (__stdcall *)())tessEdgeFlag);
	gluTessBeginPolygon(tessObj, this);

	context->device->setBlendFunc(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA);
}

void PlainPolygonRenderer::end()
{
	gluTessEndPolygon(tessObj);	
	gluDeleteTess(tessObj);

	vs->draw();
}

void PlainPolygonRenderer::beginContour()
{
	gluTessBeginContour(tessObj);
}

void PlainPolygonRenderer::endContour()
{
	gluTessEndContour(tessObj);
}

void PlainPolygonRenderer::addPoint(double x, double y)
{
	struct TessVertex *v = tessVertexBuffer.newVertex();
	Affine2 tm = context->transform;

	v->p[0] = tm.m00 * x + tm.m01 * y + tm.dx;
	v->p[1] = tm.m10 * x + tm.m11 * y + tm.dy;
	v->p[2] = 0;
	
	gluTessVertex(tessObj, v->p, v);	
}

void PlainPolygonRenderer::edgeFlag(bool edge)
{
}

void PlainPolygonRenderer::combineFunc(double coords[3], struct TessVertex *d[4], 
										   float w[4], struct TessVertex **dataOut)
{
	struct TessVertex *v = tessVertexBuffer.newVertex();
	
	v->p[0] = coords[0];
	v->p[1] = coords[1];
	v->p[2] = coords[2];
		
	*dataOut = v;
}


void PlainPolygonRenderer::vertexFunc(struct TessVertex *data)
{
	triangle[triangleIndex++] = vs->addVertex(data->p[0], data->p[1], context->color.getRGBA32());

	if(triangleIndex == 3)
	{
		vs->addTriangle(triangle[0], triangle[1], triangle[2]);
		triangleIndex = 0;
		vs->endBlock();
	}
}

